﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Reflection;
using System.Security.Cryptography;
using System.Data;
using System.Data.SQLite;
using Urd.Common;
using Urd.Packet;

namespace Urd
{
    public delegate void probar();

    class server:IDisposable
    {
        class clientinfo
        {
            IPEndPoint ipe;
            //from loginserver
            int id;
            //random generated
            int uid;
            //
            bool active;
            //
            TimeSpan average_lag;

        }

        SQLiteConnection storage;
        public DataSet ds;
        //main billboard;
        //account billboard
        //manager stack;

        //юзер шлет запрос инфы по объектам рядом. сервер шлет менегерам 
       // Dictionary<Opcode,managerinfo> registered_managers;


        /// <summary>
        /// топ менеджер принимает пакеты формата
        /// Opcode: managerinfo
        /// Command: get
        /// data: opcode интересующего менеджера.
        /// возвращает пакеты типа
        /// 
        /// -ошибка
        /// Opcode:Error
        /// c:none
        /// d:Ipaddress and port of top manager who have needed manager
        /// or nothing if not
        /// 
        /// -ответ
        /// Opcode:OK
        /// c:getOK
        /// d:Ipaddress and port
        /// 4 byte address 4 byte port;
        /// 
        /// 
        /// </summary>       
        public static configuration config=new configuration();
        
        public List<async_cached_manager> collective;
        public List<worker> workers;
        public List<managerinfo> managerinfos;
        public cache servercache;
        public Urd.Lab.topmanager topmann;
        sync_cached_manager logman;

        //class top : worker
        //{
        //    public top() : base() { }
        //    public override packet process(cache c, packet p = null)
        //    {

        //        return new packet(Opcode.Undefined, Command.WrongManager);
        //    }
        //}
        private packet log_process(cache c, packet p = null)
        {
            if (p != null) 
            {
                
                if (p.command == Command.Login) 
                {
                    
                    string query ="select world_id from login where name='"+p.Someinfo +"'";



                    object[] ret =c.Sql(query,true);
                    if (ret[0] == null) return new packet(Opcode.Error, Command.Login);
                    packet pac = new packet(Opcode.OK,Command.Login);
                    pac.Push((int)ret[0]);
                    return pac;
                }
                if (p.command == Command.New) 
                {
                    //добавить в логин новую запись
                    string query = "insert into login(id,name,world_id) values(max(id)+1,'" + p.Someinfo + "',select max(id) from position)";
                    c.Sql(query,  false);
                    return new packet(Opcode.OK,Command.Login);
                    //добавить во все остальные маны новую запись.

                }
                return new packet(Opcode.Error, Command.NotLoggedIn);
            }
            else return new packet(Opcode.Error, Command.None);
        }
        ///Todo add config to sqlite.
        ///config to remote config
        ///login to authentificate
        ///topman for storing managers data and communicating to another servers
        ///

        void setup_sqlite() 
        {
            storage = new SQLiteConnection("Data Source=server_sql.db;Version=3;New=True;");
            SQLiteDataAdapter adapter;
            
            DataTable DT = new DataTable();

            string CommandText = "select * from managerinfos";
            adapter = new SQLiteDataAdapter(CommandText, storage);
            
            adapter.Fill(DT);
            
            ds.Tables.Add(DT);
           // adapter.Fill(ds);
            
        }
        //void setup_workers() 
        //{
        //    string[] paths = System.IO.Directory.GetFiles(@"workers\", "*.dll");
           
            
        //    foreach (string path in paths)
        //    {
        //        Assembly a = Assembly.LoadFrom(path);
        //        TypeInfo o = a.DefinedTypes.ElementAt(0);
        //        if (o.BaseType.Name == "worker")
        //        {
        //            MD5Cng cng = new MD5Cng();
        //            byte[] md5hash = cng.ComputeHash(System.IO.File.ReadAllBytes(path));
        //            try
        //            {
        //                worker w = (worker)a.CreateInstance(o.FullName);
        //                // w.info.md5hash= Encoding.Unicode.GetString(md5hash);


        //                workers.Add(w);
        //            }
        //            catch { }
        //        }
        //        //   this.ToString();
        //        //   if(a.DefinedTypes[0]!=null&&a.DefinedTypes[0]
        //    }
           
            
        //}

         void setup_top_manager()
        {
            topmann.start();
            topmann.scan();
            string[] registered = topmann.RegisteredManagers;
            collective.AddRange(topmann.init_managers(registered));
            //managerinfo topinfo = new managerinfo
            //    (Opcode.ManagerInfo,
            //    Int32.Parse(config.server_bind_port),
            //    IPAddress.Parse(config.server_bind_ip_adress_or_domain),
            //    "topmanager",
            //    "managers",
            //    "managers"
            //    );
            //managerinfos.Add(topinfo);
            //collective.Add(new async_cached_manager(topinfo, new top()));

            
        }
         void setup_login_manager() 
        {
            managerinfo loginfo = new managerinfo
               (Opcode.Login,
               
               1889,
               IPAddress.Parse(config.server_bind_ip_adress_or_domain),
               "login_manager",
               "login",
               "login"
               );
            managerinfos.Add(loginfo);
           //collective.Add(new better_cached_manager(loginfo, log_process, "login"));
            logman = new sync_cached_manager(loginfo, log_process, "login");
            
        }       
        // void setup_position_manager() 
        //{
        //    managerinfo maninfo = new managerinfo
        //        (Opcode.Pos,
        //        1890,
                
        //        IPAddress.Parse(config.server_bind_ip_adress_or_domain),
        //        "positionr",
        //        "positionr",
        //        "positionr");
        //    managerinfos.Add(maninfo);


        //    Assembly a = Assembly.LoadFrom(@"workers\position.dll");
        //   object o = a.CreateInstance("Urd.Workers.positionr");
        //    Urd.Common.worker w = (worker)o;
        //     w.Name = "positionr";
        //     w.opcode = Opcode.Pos;

        //     collective.Add(new async_cached_manager(maninfo, w,false));

            
        //}


         public server() 
         {
             config.load();
             collective = new List<async_cached_manager>();
             managerinfos=new List<managerinfo>();
             workers = new List<worker>();
             servercache = new cache();
             ds = new DataSet("server");
             topmann = new Lab.topmanager(server.config.workersfolder);
             
         }
         
         public void start(probar pr)
        {
            
          //  int c = 0;
            setup_sqlite();
           // setup_workers();
            setup_top_manager();
            setup_login_manager();
            logman.start();
           // setup_position_manager();
            
            foreach (async_cached_manager m in collective) 
            {
                pr();
                m.start();
            }
            
           
        }
         public void stop() 
         {
             foreach (async_cached_manager m in collective)
             {
                 m.stop();
             }
             collective.Clear();
             managerinfos.Clear();
         }
         public void Dispose() 
         {
             servercache.Dispose();
             logman.Dispose();
         }
         public void dump() 
         {
             foreach (async_cached_manager m in collective)
             {
                 m.dump();
             }
         }

    }
}
